#pragma once
#include<string>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <csignal>
#include <sys/resource.h>
#include"../comm/log.hpp"
#include"../comm/FileTools.hpp"

using namespace Ns_Log;
using namespace Ns_FileTools;

//指定可执行文件，程序替换并执行即可
class Runner
{
public:
    //memory MB  seconds S
    static bool SrcLimit(int memory,int seconds)
    {
        struct rlimit limit;

        //设置虚拟内存限制
        limit.rlim_cur = memory * 1024 * 1024;  // 20MB
        limit.rlim_max = memory * 1024 * 1024;  // 20MB
        if (setrlimit(RLIMIT_AS, &limit) != 0) {
            return false;
        }

        limit.rlim_cur = seconds;  
        limit.rlim_max = seconds;  
        if (setrlimit(RLIMIT_CPU, &limit) != 0) {
            return false;
        }

        return true;
    }
    static void run(const std::string& filename)
    {
        //创建子进程
        pid_t pid = fork();
        if (pid==-1)
        {
            log(ERROR,"运行前创建子进程失败");
            return;
        }
        else if(pid==0)//子进程
        {
            //文件重定向
            if(!FileTools::FileRedirection(filename+".stdin",0)||
            !FileTools::FileRedirection(filename+".stdout",1)||
            !FileTools::FileRedirection(filename+".stderr",2))
            {
                log(ERROR,"运行时文件重定向失败");
                return;
            }

            //设置资源限制
            if(!SrcLimit(100,5))
            {
                log(ERROR,"运行子进程资源限制失败");
                return;
            }
            //程序替换exe
            execl(filename.c_str(), ("./"+filename).c_str(),NULL);
        }
        else//父进程
        {
            int status;
            waitpid(pid, &status, 0);
            if (WIFSIGNALED(status))
            {
                // 子进程被信号终止
                FileTools::WriteStringToFile(strsignal(WTERMSIG(status)),filename+".stderr");
            }
            else
            {
                FileTools::WriteStringToFile("run time out",filename);
            }
            log(INFO, "运行完成，运行子进程退出，状态码: "+std::to_string(status));
        }
    }
};